// Copyright 2022 The Cockroach Authors.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.

package cast

import (
	"github.com/cockroachdb/cockroach/pkg/sql/oidext"
	"github.com/cockroachdb/cockroach/pkg/sql/sem/volatility"
	"github.com/cockroachdb/errors"
	"github.com/lib/pq/oid"
)

// castMap defines valid casts. It maps from a source OID to a target OID to a
// cast struct that contains information about the cast. Some possible casts,
// such as casts from the UNKNOWN type and casts from a type to the identical
// type, are not defined in the castMap and are instead codified in ValidCast.
//
// Validation is performed on the map in init().
//
// Entries with a ContextOriginPgCast origin were automatically generated by the
// cast_map_gen.sh script. The script outputs some types that we do not support.
// Those types were manually deleted. Entries with
// ContextOriginAutomaticIOConversion origin were manually added.
var castMap = map[oid.Oid]map[oid.Oid]Cast{
	oid.T_bit: {
		oid.T_bit:    {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_int2:   {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_int4:   {MaxContext: ContextExplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_int8:   {MaxContext: ContextExplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_varbit: {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		// Automatic I/O conversions to string types.
		oid.T_bpchar:  {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_char:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_name:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_text:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
	},
	oid.T_bool: {
		oid.T_bpchar:  {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_float4:  {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_float8:  {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_int2:    {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_int4:    {MaxContext: ContextExplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_int8:    {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_numeric: {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_text:    {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		// Automatic I/O conversions to string types.
		oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
	},
	oidext.T_box2d: {
		oidext.T_geometry: {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		// Automatic I/O conversions to string types.
		oid.T_bpchar:  {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_char:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_name:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_text:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
	},
	oid.T_pg_lsn: {
		oid.T_bpchar:  {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_char:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_name:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_text:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
	},
	oidext.T_pgvector: {
		oid.T_bpchar:  {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_char:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_name:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_text:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
	},
	oid.T_bpchar: {
		oid.T_bpchar:  {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_char:    {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_name:    {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_text:    {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_varchar: {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		// Automatic I/O conversions from bpchar to other types.
		oid.T_bit:         {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_bool:        {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oidext.T_box2d:    {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_pg_lsn:      {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oidext.T_pgvector: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_bytea:       {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_date: {
			MaxContext:     ContextExplicit,
			origin:         ContextOriginAutomaticIOConversion,
			Volatility:     volatility.Stable,
			VolatilityHint: "CHAR to DATE casts depend on session DateStyle; use parse_date(string) instead",
		},
		oid.T_float4:       {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_float8:       {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oidext.T_geography: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oidext.T_geometry:  {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_inet:         {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_int2:         {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_int4:         {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_int8:         {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_interval: {
			MaxContext:     ContextExplicit,
			origin:         ContextOriginAutomaticIOConversion,
			Volatility:     volatility.Stable,
			VolatilityHint: "CHAR to INTERVAL casts depend on session IntervalStyle; use parse_interval(string) instead",
		},
		oid.T_jsonb:        {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_numeric:      {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_oid:          {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_record:       {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_refcursor:    {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_regclass:     {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_regnamespace: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_regproc:      {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_regprocedure: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_regrole:      {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_regtype:      {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_time: {
			MaxContext:     ContextExplicit,
			origin:         ContextOriginAutomaticIOConversion,
			Volatility:     volatility.Stable,
			VolatilityHint: "CHAR to TIME casts depend on session DateStyle; use parse_time(string) instead",
		},
		oid.T_timestamp: {
			MaxContext: ContextExplicit,
			origin:     ContextOriginAutomaticIOConversion,
			Volatility: volatility.Stable,
			VolatilityHint: "CHAR to TIMESTAMP casts are context-dependent because of relative timestamp strings " +
				"like 'now' and session settings such as DateStyle; use parse_timestamp(string) instead.",
		},
		oid.T_timestamptz: {
			MaxContext: ContextExplicit,
			origin:     ContextOriginAutomaticIOConversion,
			Volatility: volatility.Stable,
		},
		oid.T_timetz: {
			MaxContext:     ContextExplicit,
			origin:         ContextOriginAutomaticIOConversion,
			Volatility:     volatility.Stable,
			VolatilityHint: "CHAR to TIMETZ casts depend on session DateStyle; use parse_timetz(char) instead",
		},
		oid.T_tsquery:  {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_tsvector: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_uuid:     {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_varbit:   {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_void:     {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
	},
	oid.T_bytea: {
		oidext.T_geography: {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oidext.T_geometry:  {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_uuid:         {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		// Automatic I/O conversions to string types.
		// Casts from BYTEA to string types are stable, since they depend on
		// the bytea_output session variable.
		oid.T_bpchar:  {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_char:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_name:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_text:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
	},
	oid.T_char: {
		oid.T_bpchar:  {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_int4:    {MaxContext: ContextExplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_text:    {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		// Automatic I/O conversions to string types.
		oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		// Automatic I/O conversions from "char" to other types.
		oid.T_bit:         {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_bool:        {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oidext.T_box2d:    {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_pg_lsn:      {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oidext.T_pgvector: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_bytea:       {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_date: {
			MaxContext:     ContextExplicit,
			origin:         ContextOriginAutomaticIOConversion,
			Volatility:     volatility.Stable,
			VolatilityHint: `"char" to DATE casts depend on session DateStyle; use parse_date(string) instead`,
		},
		oid.T_float4:       {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_float8:       {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oidext.T_geography: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oidext.T_geometry:  {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_inet:         {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_int2:         {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_int8:         {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_interval: {
			MaxContext:     ContextExplicit,
			origin:         ContextOriginAutomaticIOConversion,
			Volatility:     volatility.Stable,
			VolatilityHint: `"char" to INTERVAL casts depend on session IntervalStyle; use parse_interval(string) instead`,
		},
		oid.T_jsonb:        {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_numeric:      {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_oid:          {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_record:       {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_refcursor:    {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_regclass:     {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_regnamespace: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_regproc:      {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_regprocedure: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_regrole:      {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_regtype:      {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_time: {
			MaxContext:     ContextExplicit,
			origin:         ContextOriginAutomaticIOConversion,
			Volatility:     volatility.Stable,
			VolatilityHint: `"char" to TIME casts depend on session DateStyle; use parse_time(string) instead`,
		},
		oid.T_timestamp: {
			MaxContext: ContextExplicit,
			origin:     ContextOriginAutomaticIOConversion,
			Volatility: volatility.Stable,
			VolatilityHint: `"char" to TIMESTAMP casts are context-dependent because of relative timestamp strings ` +
				"like 'now' and session settings such as DateStyle; use parse_timestamp(string) instead.",
		},
		oid.T_timestamptz: {
			MaxContext: ContextExplicit,
			origin:     ContextOriginAutomaticIOConversion,
			Volatility: volatility.Stable,
		},
		oid.T_timetz: {
			MaxContext:     ContextExplicit,
			origin:         ContextOriginAutomaticIOConversion,
			Volatility:     volatility.Stable,
			VolatilityHint: `"char" to TIMETZ casts depend on session DateStyle; use parse_timetz(string) instead`,
		},
		oid.T_tsquery:  {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_tsvector: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_uuid:     {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_varbit:   {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_void:     {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
	},
	oid.T_date: {
		oid.T_float4:      {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_float8:      {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_int2:        {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_int4:        {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_int8:        {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_numeric:     {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_timestamp:   {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_timestamptz: {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Stable},
		// Automatic I/O conversions to string types.
		oid.T_bpchar: {
			MaxContext: ContextAssignment,
			origin:     ContextOriginAutomaticIOConversion,
			Volatility: volatility.Stable,
			VolatilityHint: "DATE to CHAR casts are dependent on DateStyle; consider " +
				"using to_char(date) instead.",
		},
		oid.T_char: {
			MaxContext: ContextAssignment,
			origin:     ContextOriginAutomaticIOConversion,
			Volatility: volatility.Stable,
			VolatilityHint: `DATE to "char" casts are dependent on DateStyle; consider ` +
				"using to_char(date) instead.",
		},
		oid.T_name: {
			MaxContext: ContextAssignment,
			origin:     ContextOriginAutomaticIOConversion,
			Volatility: volatility.Stable,
			VolatilityHint: "DATE to NAME casts are dependent on DateStyle; consider " +
				"using to_char(date) instead.",
		},
		oid.T_text: {
			MaxContext: ContextAssignment,
			origin:     ContextOriginAutomaticIOConversion,
			Volatility: volatility.Stable,
			VolatilityHint: "DATE to STRING casts are dependent on DateStyle; consider " +
				"using to_char(date) instead.",
		},
		oid.T_varchar: {
			MaxContext: ContextAssignment,
			origin:     ContextOriginAutomaticIOConversion,
			Volatility: volatility.Stable,
			VolatilityHint: "DATE to VARCHAR casts are dependent on DateStyle; consider " +
				"using to_char(date) instead.",
		},
	},
	oid.T_float4: {
		oid.T_bool:     {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_float8:   {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_int2:     {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_int4:     {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_int8:     {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_interval: {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_numeric:  {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		// Automatic I/O conversions to string types.
		// Casts from FLOAT4 to string types are stable, since they depend on the
		// extra_float_digits session variable.
		oid.T_bpchar:  {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_char:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_name:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_text:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
	},
	oid.T_float8: {
		oid.T_bool:     {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_float4:   {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_int2:     {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_int4:     {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_int8:     {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_interval: {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_numeric:  {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		// Automatic I/O conversions to string types.
		// Casts from FLOAT8 to string types are stable, since they depend on the
		// extra_float_digits session variable.
		oid.T_bpchar:  {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_char:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_name:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_text:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
	},
	oidext.T_geography: {
		oid.T_bytea:        {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oidext.T_geography: {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oidext.T_geometry:  {MaxContext: ContextExplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_jsonb:        {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		// Automatic I/O conversions to string types.
		oid.T_bpchar:  {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_char:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_name:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_text:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
	},
	oidext.T_geometry: {
		oidext.T_box2d:     {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_bytea:        {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oidext.T_geography: {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oidext.T_geometry:  {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_jsonb:        {MaxContext: ContextExplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_text:         {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		// Automatic I/O conversions to string types.
		oid.T_bpchar:  {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_char:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_name:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
	},
	oid.T_inet: {
		oid.T_bpchar:  {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_text:    {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		// Automatic I/O conversions to string types.
		oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
	},
	oid.T_int2: {
		oid.T_bool:         {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_date:         {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_float4:       {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_float8:       {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_int4:         {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_int8:         {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_interval:     {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_numeric:      {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_oid:          {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_regclass:     {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_regnamespace: {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_regproc:      {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_regprocedure: {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_regrole:      {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_regtype:      {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_timestamp:    {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_timestamptz:  {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		// Automatic I/O conversions to string types.
		oid.T_bpchar:  {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_char:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_name:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_text:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
	},
	oid.T_int4: {
		oid.T_bit:          {MaxContext: ContextExplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_bool:         {MaxContext: ContextExplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_char:         {MaxContext: ContextExplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_date:         {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_float4:       {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_float8:       {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_int2:         {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_int8:         {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_interval:     {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_numeric:      {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_oid:          {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_regclass:     {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_regnamespace: {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_regproc:      {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_regprocedure: {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_regrole:      {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_regtype:      {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_timestamp:    {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_timestamptz:  {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		// Automatic I/O conversions to string types.
		oid.T_bpchar:  {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_name:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_text:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
	},
	oid.T_int8: {
		oid.T_bit:          {MaxContext: ContextExplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_bool:         {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_date:         {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_float4:       {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_float8:       {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_int2:         {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_int4:         {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_interval:     {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_numeric:      {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_oid:          {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_regclass:     {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_regnamespace: {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_regproc:      {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_regprocedure: {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_regrole:      {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_regtype:      {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_timestamp:    {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_timestamptz:  {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		// Automatic I/O conversions to string types.
		oid.T_bpchar:  {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_char:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_name:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_text:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
	},
	oid.T_interval: {
		oid.T_float4:   {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_float8:   {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_int2:     {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_int4:     {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_int8:     {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_interval: {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_numeric:  {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_time:     {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		// Automatic I/O conversions to string types.
		oid.T_bpchar: {
			MaxContext:     ContextAssignment,
			origin:         ContextOriginAutomaticIOConversion,
			Volatility:     volatility.Stable,
			VolatilityHint: "INTERVAL to CHAR casts depend on IntervalStyle; consider using to_char(interval)",
		},
		oid.T_char: {
			MaxContext:     ContextAssignment,
			origin:         ContextOriginAutomaticIOConversion,
			Volatility:     volatility.Stable,
			VolatilityHint: `INTERVAL to "char" casts depend on IntervalStyle; consider using to_char(interval)`,
		},
		oid.T_name: {
			MaxContext:     ContextAssignment,
			origin:         ContextOriginAutomaticIOConversion,
			Volatility:     volatility.Stable,
			VolatilityHint: "INTERVAL to NAME casts depend on IntervalStyle; consider using to_char(interval)",
		},
		oid.T_text: {
			MaxContext:     ContextAssignment,
			origin:         ContextOriginAutomaticIOConversion,
			Volatility:     volatility.Stable,
			VolatilityHint: "INTERVAL to STRING casts depend on IntervalStyle; consider using to_char(interval)",
		},
		oid.T_varchar: {
			MaxContext:     ContextAssignment,
			origin:         ContextOriginAutomaticIOConversion,
			Volatility:     volatility.Stable,
			VolatilityHint: "INTERVAL to VARCHAR casts depend on IntervalStyle; consider using to_char(interval)",
		},
	},
	oid.T_jsonb: {
		oid.T_bool:         {MaxContext: ContextExplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_float4:       {MaxContext: ContextExplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_float8:       {MaxContext: ContextExplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oidext.T_geography: {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oidext.T_geometry:  {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_int2:         {MaxContext: ContextExplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_int4:         {MaxContext: ContextExplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_int8:         {MaxContext: ContextExplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_numeric:      {MaxContext: ContextExplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		// Automatic I/O conversions to string types.
		oid.T_bpchar:  {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_char:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_name:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_text:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
	},
	oid.T_name: {
		oid.T_bpchar:  {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_text:    {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Leakproof},
		oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		// Automatic I/O conversions to string types.
		oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		// Automatic I/O conversions from NAME to other types.
		oid.T_bit:         {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_bool:        {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oidext.T_box2d:    {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_pg_lsn:      {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oidext.T_pgvector: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_bytea:       {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_date: {
			MaxContext:     ContextExplicit,
			origin:         ContextOriginAutomaticIOConversion,
			Volatility:     volatility.Stable,
			VolatilityHint: "NAME to DATE casts depend on session DateStyle; use parse_date(string) instead",
		},
		oid.T_float4:       {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_float8:       {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oidext.T_geography: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oidext.T_geometry:  {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_inet:         {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_int2:         {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_int4:         {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_int8:         {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_interval: {
			MaxContext:     ContextExplicit,
			origin:         ContextOriginAutomaticIOConversion,
			Volatility:     volatility.Stable,
			VolatilityHint: "NAME to INTERVAL casts depend on session IntervalStyle; use parse_interval(string) instead",
		},
		oid.T_jsonb:        {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_numeric:      {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_oid:          {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_record:       {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_refcursor:    {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_regclass:     {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_regnamespace: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_regproc:      {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_regprocedure: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_regrole:      {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_regtype:      {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_time: {
			MaxContext:     ContextExplicit,
			origin:         ContextOriginAutomaticIOConversion,
			Volatility:     volatility.Stable,
			VolatilityHint: "NAME to TIME casts depend on session DateStyle; use parse_time(string) instead",
		},
		oid.T_timestamp: {
			MaxContext: ContextExplicit,
			origin:     ContextOriginAutomaticIOConversion,
			Volatility: volatility.Stable,
			VolatilityHint: "NAME to TIMESTAMP casts are context-dependent because of relative timestamp strings " +
				"like 'now' and session settings such as DateStyle; use parse_timestamp(string) instead.",
		},
		oid.T_timestamptz: {
			MaxContext: ContextExplicit,
			origin:     ContextOriginAutomaticIOConversion,
			Volatility: volatility.Stable,
		},
		oid.T_timetz: {
			MaxContext:     ContextExplicit,
			origin:         ContextOriginAutomaticIOConversion,
			Volatility:     volatility.Stable,
			VolatilityHint: "NAME to TIMETZ casts depend on session DateStyle; use parse_timetz(string) instead",
		},
		oid.T_tsquery:  {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_tsvector: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_uuid:     {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_varbit:   {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_void:     {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
	},
	oid.T_numeric: {
		oid.T_bool:     {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_float4:   {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_float8:   {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_int2:     {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_int4:     {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_int8:     {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_interval: {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_numeric:  {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		// Automatic I/O conversions to string types.
		oid.T_bpchar:  {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_char:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_name:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_text:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
	},
	oid.T_oid: {
		// TODO(mgartner): Casts to INT2 should not be allowed.
		oid.T_int2:         {MaxContext: ContextAssignment, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_int4:         {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_int8:         {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_regclass:     {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_regnamespace: {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_regproc:      {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_regprocedure: {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_regrole:      {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_regtype:      {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		// Automatic I/O conversions to string types.
		oid.T_bpchar:  {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_char:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_name:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_text:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
	},
	oid.T_record: {
		// Automatic I/O conversions to string types.
		oid.T_bpchar:  {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_char:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_name:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_text:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
	},
	oid.T_refcursor: {
		// The REFCURSOR data type has no casts in the pg_cast table; all of its
		// casts are the I/O casts for string types.
		//
		// Automatic I/O conversions to string types.
		oid.T_bpchar:  {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_char:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_name:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Leakproof},
		oid.T_text:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
	},
	oid.T_regclass: {
		// TODO(mgartner): Casts to INT2 should not be allowed.
		oid.T_int2:         {MaxContext: ContextAssignment, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_int4:         {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_int8:         {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_oid:          {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_regnamespace: {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Stable},
		oid.T_regproc:      {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Stable},
		oid.T_regprocedure: {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Stable},
		oid.T_regrole:      {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Stable},
		oid.T_regtype:      {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Stable},
		// Automatic I/O conversions to string types.
		oid.T_bpchar:  {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_char:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_name:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_text:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
	},
	oid.T_regnamespace: {
		// TODO(mgartner): Casts to INT2 should not be allowed.
		oid.T_int2:         {MaxContext: ContextAssignment, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_int4:         {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_int8:         {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_oid:          {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_regclass:     {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Stable},
		oid.T_regproc:      {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Stable},
		oid.T_regprocedure: {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Stable},
		oid.T_regrole:      {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Stable},
		oid.T_regtype:      {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Stable},
		// Automatic I/O conversions to string types.
		oid.T_bpchar:  {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_char:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_name:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_text:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
	},
	oid.T_regproc: {
		// TODO(mgartner): Casts to INT2 should not be allowed.
		oid.T_int2:         {MaxContext: ContextAssignment, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_int4:         {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_int8:         {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_oid:          {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_regprocedure: {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_regclass:     {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Stable},
		oid.T_regnamespace: {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Stable},
		oid.T_regrole:      {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Stable},
		oid.T_regtype:      {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Stable},
		// Automatic I/O conversions to string types.
		oid.T_bpchar:  {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_char:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_name:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_text:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
	},
	oid.T_regprocedure: {
		// TODO(mgartner): Casts to INT2 should not be allowed.
		oid.T_int2:         {MaxContext: ContextAssignment, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_int4:         {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_int8:         {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_oid:          {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_regproc:      {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_regclass:     {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Stable},
		oid.T_regnamespace: {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Stable},
		oid.T_regrole:      {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Stable},
		oid.T_regtype:      {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Stable},
		// Automatic I/O conversions to string types.
		oid.T_bpchar:  {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_char:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_name:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_text:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
	},
	oid.T_regrole: {
		// TODO(mgartner): Casts to INT2 should not be allowed.
		oid.T_int2:         {MaxContext: ContextAssignment, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_int4:         {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_int8:         {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_oid:          {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_regclass:     {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Stable},
		oid.T_regnamespace: {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Stable},
		oid.T_regproc:      {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Stable},
		oid.T_regprocedure: {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Stable},
		oid.T_regtype:      {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Stable},
		// Automatic I/O conversions to string types.
		oid.T_bpchar:  {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_char:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_name:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_text:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
	},
	oid.T_regtype: {
		// TODO(mgartner): Casts to INT2 should not be allowed.
		oid.T_int2:         {MaxContext: ContextAssignment, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_int4:         {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_int8:         {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_oid:          {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_regclass:     {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Stable},
		oid.T_regnamespace: {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Stable},
		oid.T_regproc:      {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Stable},
		oid.T_regprocedure: {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Stable},
		oid.T_regrole:      {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Stable},
		// Automatic I/O conversions to string types.
		oid.T_bpchar:  {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_char:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_name:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_text:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
	},
	oid.T_text: {
		oid.T_bpchar:      {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_char:        {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oidext.T_geometry: {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_name:        {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Leakproof},
		oid.T_regclass:    {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Stable},
		// We include a TEXT->TEXT entry to mimic the VARCHAR->VARCHAR entry
		// that is included in the pg_cast table. Postgres doesn't include a
		// TEXT->TEXT entry because it does not allow width-limited TEXT types,
		// so a cast from TEXT->TEXT is always a trivial no-op because the types
		// are always identical (see ValidCast). Because we support
		// width-limited TEXT types with STRING(n), it is possible to have
		// non-identical TEXT types. So, we must include a TEXT->TEXT entry so
		// that casts from STRING(n)->STRING(m) are valid.
		//
		// TODO(#72980): If we use the VARCHAR OID for STRING(n) types rather
		// then the TEXT OID, and we can remove this entry.
		oid.T_text:    {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_varchar: {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		// Automatic I/O conversions from TEXT to other types.
		oid.T_bit:         {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_bool:        {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oidext.T_box2d:    {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_pg_lsn:      {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oidext.T_pgvector: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_bytea:       {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_date: {
			MaxContext:     ContextExplicit,
			origin:         ContextOriginAutomaticIOConversion,
			Volatility:     volatility.Stable,
			VolatilityHint: "STRING to DATE casts depend on session DateStyle; use parse_date(string) instead",
		},
		oid.T_float4:       {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_float8:       {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oidext.T_geography: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_inet:         {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_int2:         {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_int4:         {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_int8:         {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_interval: {
			MaxContext:     ContextExplicit,
			origin:         ContextOriginAutomaticIOConversion,
			Volatility:     volatility.Stable,
			VolatilityHint: "STRING to INTERVAL casts depend on session IntervalStyle; use parse_interval(string) instead",
		},
		oid.T_jsonb:        {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_numeric:      {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_oid:          {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_record:       {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_refcursor:    {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_regnamespace: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_regproc:      {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_regprocedure: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_regrole:      {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_regtype:      {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_time: {
			MaxContext:     ContextExplicit,
			origin:         ContextOriginAutomaticIOConversion,
			Volatility:     volatility.Stable,
			VolatilityHint: "STRING to TIME casts depend on session DateStyle; use parse_time(string) instead",
		},
		oid.T_timestamp: {
			MaxContext: ContextExplicit,
			origin:     ContextOriginAutomaticIOConversion,
			Volatility: volatility.Stable,
			VolatilityHint: "STRING to TIMESTAMP casts are context-dependent because of relative timestamp strings " +
				"like 'now' and session settings such as DateStyle; use parse_timestamp(string) instead.",
		},
		oid.T_timestamptz: {
			MaxContext: ContextExplicit,
			origin:     ContextOriginAutomaticIOConversion,
			Volatility: volatility.Stable,
		},
		oid.T_timetz: {
			MaxContext:     ContextExplicit,
			origin:         ContextOriginAutomaticIOConversion,
			Volatility:     volatility.Stable,
			VolatilityHint: "STRING to TIMETZ casts depend on session DateStyle; use parse_timetz(string) instead",
		},
		oid.T_tsquery:  {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_tsvector: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_uuid:     {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_varbit:   {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_void:     {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
	},
	oid.T_time: {
		oid.T_interval: {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_time:     {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_timetz:   {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Stable},
		// Automatic I/O conversions to string types.
		oid.T_bpchar:  {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_char:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_name:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_text:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
	},
	oid.T_timestamp: {
		oid.T_date:        {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_float4:      {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_float8:      {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_int2:        {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_int4:        {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_int8:        {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_numeric:     {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_time:        {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_timestamp:   {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_timestamptz: {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Stable},
		// Automatic I/O conversions to string types.
		oid.T_bpchar: {
			MaxContext: ContextAssignment,
			origin:     ContextOriginAutomaticIOConversion,
			Volatility: volatility.Stable,
			VolatilityHint: "TIMESTAMP to CHAR casts are dependent on DateStyle; consider " +
				"using to_char(timestamp) instead.",
		},
		oid.T_char: {
			MaxContext: ContextAssignment,
			origin:     ContextOriginAutomaticIOConversion,
			Volatility: volatility.Stable,
			VolatilityHint: `TIMESTAMP to "char" casts are dependent on DateStyle; consider ` +
				"using to_char(timestamp) instead.",
		},
		oid.T_name: {
			MaxContext: ContextAssignment,
			origin:     ContextOriginAutomaticIOConversion,
			Volatility: volatility.Stable,
			VolatilityHint: "TIMESTAMP to NAME casts are dependent on DateStyle; consider " +
				"using to_char(timestamp) instead.",
		},
		oid.T_text: {
			MaxContext: ContextAssignment,
			origin:     ContextOriginAutomaticIOConversion,
			Volatility: volatility.Stable,
			VolatilityHint: "TIMESTAMP to STRING casts are dependent on DateStyle; consider " +
				"using to_char(timestamp) instead.",
		},
		oid.T_varchar: {
			MaxContext: ContextAssignment,
			origin:     ContextOriginAutomaticIOConversion,
			Volatility: volatility.Stable,
			VolatilityHint: "TIMESTAMP to VARCHAR casts are dependent on DateStyle; consider " +
				"using to_char(timestamp) instead.",
		},
	},
	oid.T_timestamptz: {
		oid.T_date:    {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Stable},
		oid.T_float4:  {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_float8:  {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_int2:    {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_int4:    {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_int8:    {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_numeric: {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_time:    {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Stable},
		oid.T_timestamp: {
			MaxContext:     ContextAssignment,
			origin:         ContextOriginPgCast,
			Volatility:     volatility.Stable,
			VolatilityHint: "TIMESTAMPTZ to TIMESTAMP casts depend on the current timezone; consider using AT TIME ZONE 'UTC' instead",
		},
		oid.T_timestamptz: {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_timetz:      {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Stable},
		// Automatic I/O conversions to string types.
		oid.T_bpchar: {
			MaxContext: ContextAssignment,
			origin:     ContextOriginAutomaticIOConversion,
			Volatility: volatility.Stable,
			VolatilityHint: "TIMESTAMPTZ to CHAR casts depend on the current timezone; consider " +
				"using to_char(t AT TIME ZONE 'UTC') instead.",
		},
		oid.T_char: {
			MaxContext: ContextAssignment,
			origin:     ContextOriginAutomaticIOConversion,
			Volatility: volatility.Stable,
			VolatilityHint: `TIMESTAMPTZ to "char" casts depend on the current timezone; consider ` +
				"using to_char(t AT TIME ZONE 'UTC') instead.",
		},
		oid.T_name: {
			MaxContext: ContextAssignment,
			origin:     ContextOriginAutomaticIOConversion,
			Volatility: volatility.Stable,
			VolatilityHint: "TIMESTAMPTZ to NAME casts depend on the current timezone; consider " +
				"using to_char(t AT TIME ZONE 'UTC') instead.",
		},
		oid.T_text: {
			MaxContext: ContextAssignment,
			origin:     ContextOriginAutomaticIOConversion,
			Volatility: volatility.Stable,
			VolatilityHint: "TIMESTAMPTZ to STRING casts depend on the current timezone; consider " +
				"using to_char(t AT TIME ZONE 'UTC') instead.",
		},
		oid.T_varchar: {
			MaxContext: ContextAssignment,
			origin:     ContextOriginAutomaticIOConversion,
			Volatility: volatility.Stable,
			VolatilityHint: "TIMESTAMPTZ to VARCHAR casts depend on the current timezone; consider " +
				"using to_char(t AT TIME ZONE 'UTC') instead.",
		},
	},
	oid.T_timetz: {
		oid.T_time:   {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_timetz: {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		// Automatic I/O conversions to string types.
		oid.T_bpchar:  {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_char:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_name:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_text:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
	},
	oid.T_tsvector: {
		// Automatic I/O conversions to string types.
		oid.T_bpchar:  {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_char:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_name:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_text:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
	},
	oid.T_tsquery: {
		// Automatic I/O conversions to string types.
		oid.T_bpchar:  {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_char:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_name:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_text:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
	},
	oid.T_uuid: {
		oid.T_bytea: {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		// Automatic I/O conversions to string types.
		oid.T_bpchar:  {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_char:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_name:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_text:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
	},
	oid.T_varbit: {
		oid.T_bit:    {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_int2:   {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_int4:   {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_int8:   {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable},
		oid.T_varbit: {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		// Automatic I/O conversions to string types.
		oid.T_bpchar:  {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_char:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_name:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_text:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
	},
	oid.T_varchar: {
		oid.T_bpchar:   {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_char:     {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_name:     {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_regclass: {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Stable},
		oid.T_text:     {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		oid.T_varchar:  {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable},
		// Automatic I/O conversions from VARCHAR to other types.
		oid.T_bit:         {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_bool:        {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oidext.T_box2d:    {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_pg_lsn:      {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oidext.T_pgvector: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_bytea:       {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_date: {
			MaxContext:     ContextExplicit,
			origin:         ContextOriginAutomaticIOConversion,
			Volatility:     volatility.Stable,
			VolatilityHint: "VARCHAR to DATE casts depend on session DateStyle; use parse_date(string) instead",
		},
		oid.T_float4:       {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_float8:       {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oidext.T_geography: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oidext.T_geometry:  {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_inet:         {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_int2:         {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_int4:         {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_int8:         {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_interval: {
			MaxContext:     ContextExplicit,
			origin:         ContextOriginAutomaticIOConversion,
			Volatility:     volatility.Stable,
			VolatilityHint: "VARCHAR to INTERVAL casts depend on session IntervalStyle; use parse_interval(string) instead",
		},
		oid.T_jsonb:        {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_numeric:      {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_oid:          {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_record:       {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_refcursor:    {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_regnamespace: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_regproc:      {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_regprocedure: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_regrole:      {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_regtype:      {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable},
		oid.T_time: {
			MaxContext:     ContextExplicit,
			origin:         ContextOriginAutomaticIOConversion,
			Volatility:     volatility.Stable,
			VolatilityHint: "VARCHAR to TIME casts depend on session DateStyle; use parse_time(string) instead",
		},
		oid.T_timestamp: {
			MaxContext: ContextExplicit,
			origin:     ContextOriginAutomaticIOConversion,
			Volatility: volatility.Stable,
			VolatilityHint: "VARCHAR to TIMESTAMP casts are context-dependent because of relative timestamp strings " +
				"like 'now' and session settings such as DateStyle; use parse_timestamp(string) instead.",
		},
		oid.T_timestamptz: {
			MaxContext: ContextExplicit,
			origin:     ContextOriginAutomaticIOConversion,
			Volatility: volatility.Stable,
		},
		oid.T_timetz: {
			MaxContext:     ContextExplicit,
			origin:         ContextOriginAutomaticIOConversion,
			Volatility:     volatility.Stable,
			VolatilityHint: "VARCHAR to TIMETZ casts depend on session DateStyle; use parse_timetz(string) instead",
		},
		oid.T_tsquery:  {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_tsvector: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_uuid:     {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_varbit:   {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_void:     {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
	},
	oid.T_void: {
		oid.T_bpchar:  {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_char:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_name:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_text:    {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
		oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable},
	},
}

// init performs sanity checks on castMap.
func init() {
	var stringTypes = [...]oid.Oid{
		oid.T_bpchar,
		oid.T_name,
		oid.T_char,
		oid.T_varchar,
		oid.T_text,
	}
	isStringType := func(o oid.Oid) bool {
		for _, strOid := range stringTypes {
			if o == strOid {
				return true
			}
		}
		return false
	}

	typeName := func(o oid.Oid) string {
		if name, ok := oidext.TypeName(o); ok {
			return name
		}
		panic(errors.AssertionFailedf("no type name for oid %d", o))
	}

	// Assert that there is a cast to and from every string type.
	for _, strType := range stringTypes {
		for otherType := range castMap {
			if strType == otherType {
				continue
			}
			strTypeName := typeName(strType)
			otherTypeName := typeName(otherType)
			if _, from := castMap[strType][otherType]; !from && otherType != oid.T_unknown {
				panic(errors.AssertionFailedf("there must be a cast from %s to %s", strTypeName, otherTypeName))
			}
			if _, to := castMap[otherType][strType]; !to {
				panic(errors.AssertionFailedf("there must be a cast from %s to %s", otherTypeName, strTypeName))
			}
		}
	}

	// Assert that each cast is valid.
	for src, tgts := range castMap {
		for tgt, ent := range tgts {
			srcStr := typeName(src)
			tgtStr := typeName(tgt)

			// Assert that MaxContext, method, and origin have been set.
			if ent.MaxContext == Context(0) {
				panic(errors.AssertionFailedf("cast from %s to %s has no MaxContext set", srcStr, tgtStr))
			}
			if ent.origin == ContextOrigin(0) {
				panic(errors.AssertionFailedf("cast from %s to %s has no origin set", srcStr, tgtStr))
			}

			// Casts from a type to the same type should be implicit.
			if src == tgt {
				if ent.MaxContext != ContextImplicit {
					panic(errors.AssertionFailedf(
						"cast from %s to %s must be an implicit cast",
						srcStr, tgtStr,
					))
				}
			}

			// Automatic I/O conversions to string types are assignment casts.
			if isStringType(tgt) && ent.origin == ContextOriginAutomaticIOConversion &&
				ent.MaxContext != ContextAssignment {
				panic(errors.AssertionFailedf(
					"automatic conversion from %s to %s must be an assignment cast",
					srcStr, tgtStr,
				))
			}

			// Automatic I/O conversions from string types are explicit casts.
			if isStringType(src) && !isStringType(tgt) && ent.origin == ContextOriginAutomaticIOConversion &&
				ent.MaxContext != ContextExplicit {
				panic(errors.AssertionFailedf(
					"automatic conversion from %s to %s must be an explicit cast",
					srcStr, tgtStr,
				))
			}
		}
	}
}
